<!--
  文件上传组件 - UploadFile.vue
  
  功能特性：
  1. 支持单文件和多文件上传
  2. 当 multiple=true 时，支持批量上传图片
  3. 使用异步同时调用上传接口，提高上传效率
  4. 实时显示上传进度
  5. 支持拖拽上传
  
  使用方法：
  <UploadFile 
    v-model="fileUrls" 
    :multiple="true" 
    @change="handleFileChange"
  />
  
  Props:
  - value: 文件URL字符串，多个文件用逗号分隔
  - multiple: 是否支持多文件上传，默认 false
  - fileType: 文件类型限制，可选值：'image', 'video', 'audio' 或空字符串（所有类型）
  
  Events:
  - change: 文件列表变化时触发，参数为逗号分隔的文件URL字符串
-->

<template>
  <div class="file-upload-wrapper">
    <!-- 显示已选择的文件 -->
    <div
      v-loading="loading"
      class="img-upload-box"
      element-loading-spinner="el-icon-loading"
      element-loading-background="rgba(255, 255, 255, 0.6)"
    >
      <div v-for="(file,index) in fileList" :key="index" class="avatar-uploader" :class="[isVideo(file) ? 'video-container' : '', multiple ? 'multiple' : '']">
        <!-- 视频预览 -->
        <video
            v-if="isVideo(file)"
            style="width: 100%; height: 100%"
            controls
            :src="file"
        >
          您的浏览器不支持视频播放
        </video>
        <!-- 图片预览 -->
        <el-image
            v-else
            style="width: 100%; height: 100%"
            :preview-src-list="fileList"
            :src="file"
            fit="contain"
        >
          <template #error>
            <img src="@/assets/file.png" alt="" fit="contain" style="width: 100%">
          </template>
        </el-image>
        <i class="el-icon-error close-icon" @click="onClose(index)" />
      </div>

      <!-- 点击打开文件选择器对话框 -->
      <div v-if="multiple || !fileList.length" :class="['avatar-uploader active', multiple ? 'multiple' : '']" @click="openFileDialog">
        <i class="el-icon-plus avatar-uploader-icon" />
      </div>
      <slot />
    </div>

    <!-- 文件选择器对话框 -->
    <el-dialog
      title="选择文件"
      :visible.sync="uploadDialogVisible"
      width="1000px"
      append-to-body
      :close-on-click-modal="false"
      :before-close="handleDialogClose"
    >
      <!-- 引入文件管理页面组件，传入选择模式参数 -->
      <FileManager
        ref="fileManager"
        :selectable="true"
        :multiple="multiple"
        :selected-files="selectedFiles"
        @file-selected="onFileSelected"
      />

      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="confirmSelection">确 定</el-button>
      </span>
    </el-dialog>

    <!-- 上传文件对话框 -->
    <el-dialog
      title="上传文件"
      :visible.sync="dialogVisible"
      width="600px"
      :close-on-click-modal="false"
      :append-to-body="true"
    >
      <el-upload
        v-if="dialogVisible"
        style="width: 100%;"
        class="upload-container"
        drag
        action=""
        :http-request="handleFileUpload"
        :limit="multiple ? 10 : 1"
        :multiple="multiple"
        :show-file-list="true"
        :file-list="uploadFileList"
        :on-change="handleFileChange"
        :on-remove="handleFileRemove"
        :auto-upload="false"
        :accept="accept"
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">
          将文件拖到此处，或<em>点击上传</em>
          <br>
          <small v-if="multiple">支持多文件上传，最多10个文件</small>
          <br>
          <small style="color: #409eff;">选择文件后自动开始上传</small>
        </div>
      </el-upload>

      <!-- 上传进度显示 -->
      <div v-if="uploadProgress.length > 0" class="upload-progress">
        <div v-for="(progress, index) in uploadProgress" :key="index" class="progress-item">
          <div class="progress-info">
            <span class="filename">{{ progress.filename }}</span>
            <span :class="['status', progress.status]">
              {{ progress.status === 'uploading' ? '上传中' : progress.status === 'success' ? '成功' : '失败' }}
            </span>
          </div>
          <el-progress 
            :percentage="progress.percentage" 
            :status="progress.status === 'error' ? 'exception' : progress.status === 'success' ? 'success' : ''"
          />
        </div>
      </div>

      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import { uploadFile, http } from '@/api'
import dayjs from 'dayjs'
import FileManager from '@/views/file/index.vue'

export default {
  name: 'FileUpload',
  components: {
    FileManager
  },
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
    value: {
      type: String,
      default: ''
    },
    multiple: {
      type: Boolean,
      default: false
    },
    accept: {
      type: String,
      default: 'image/*' // 图片格式： */
    }
  },
  data() {
    return {
      loading: false,
      fileList: [],
      dialogVisible: false,
      uploadDialogVisible: false,
      selectedFiles: [],
      tempSelectedFiles: [],
      uploadFileList: [], // 用于 el-upload 的 file-list
      uploadProgress: [], // 用于显示上传进度
      batchUploading: false, // 批量上传时的加载状态
      uploadedCount: 0, // 已上传完成的文件数量
      totalCount: 0, // 总文件数量
      uploadingFiles: new Set() // 正在上传的文件集合，防止重复上传
    }
  },
  watch: {
    value: {
      handler(val) {
        this.fileList = (val || '').split(',').filter(el => el)
      },
      immediate: true,
      deep: true
    }
  },
  methods: {
    // 显示上传对话框
    showUploadDialog() {
      this.dialogVisible = true;
      this.uploadFileList = []; // 清空上传列表
      this.uploadProgress = []; // 清空进度显示
      this.uploadingFiles.clear(); // 清空正在上传的文件集合
    },

    // 打开文件选择器对话框
    openFileDialog() {
      this.dialogVisible = true
      this.tempSelectedFiles = [...this.fileList] // 保存当前选择，以便取消时恢复
      // this.loadFiles()
    },

    // 当文件管理器选择文件时的回调
    onFileSelected(files) {
      this.selectedFiles = files
    },

    // 处理文件上传（单文件模式直接上传）
    async handleFileUpload({ file }) {
      // 单文件和多文件模式都由 handleFileChange 触发，这里不直接处理
      // 避免重复上传，统一由 startSingleUpload 和 startBatchUpload 处理
    },



    // 确认选择
    confirmSelection() {
      const selectedFiles = this.$refs.fileManager.getSelectedFiles()
      const urls = selectedFiles.map(file => file.file_url)

      if (this.multiple) {
        this.fileList = urls
      } else if (urls.length > 0) {
        this.fileList = [urls[0]]
      } else {
        this.fileList = []
      }

      this.$emit('change', this.fileList.join(','))
      this.dialogVisible = false
    },

    // 关闭对话框
    handleDialogClose() {
      // 恢复之前的选择
      this.fileList = [...this.tempSelectedFiles]
      this.dialogVisible = false
    },

    // 移除文件
    onClose(index) {
      this.fileList.splice(index, 1)
      this.$emit('change', this.fileList.join(','))
    },

    // 文件类型判断
    isImage(file) {
      return file.endsWith('.png') || file.endsWith('.jpg') || file.endsWith('.jpeg')
    },

    isVideo(file) {
      return file.endsWith('.mp4')
    },

    isImageFile(type) {
      return type && (type.startsWith('image/') || type === 'image')
    },

    isAudioFile(type) {
      return type && (type.startsWith('audio/') || type === 'audio')
    },

    isVideoFile(type) {
      return type && (type.startsWith('video/') || type === 'video')
    },

    // 格式化文件大小
    formatFileSize(bytes) {
      if (!bytes || bytes === 0) return '0 B'
      const k = 1024
      const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
      const i = Math.floor(Math.log(bytes) / Math.log(k))
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
    },

    // 截断文件名
    truncateFilename(filename) {
      if (!filename) return ''
      if (filename.length <= 15) return filename
      const ext = filename.lastIndexOf('.') > 0 ? filename.substring(filename.lastIndexOf('.')) : ''
      const name = filename.substring(0, filename.length - ext.length)
      return name.substring(0, 10) + '...' + (ext ? ext : '')
    },

    // 处理 el-upload 的 file-list 变化
    handleFileChange(file, fileList) {
      this.uploadFileList = fileList;
      
      // 如果是多文件模式，且当前没有在上传，且文件列表有变化，则开始批量上传
      if (this.multiple && !this.batchUploading && fileList.length > 0) {
        // 延迟一点时间，避免重复触发
        this.$nextTick(() => {
          this.startBatchUpload();
        });
      }
      // 如果是单文件模式，且当前没有在上传，且文件列表有变化，则开始单文件上传
      else if (!this.multiple && !this.batchUploading && fileList.length > 0) {
        // 延迟一点时间，避免重复触发
        this.$nextTick(() => {
          this.startSingleUpload();
        });
      }
    },

    // 处理 el-upload 的文件移除
    handleFileRemove(file, fileList) {
      this.uploadFileList = fileList;
    },

    // 开始单文件上传
    async startSingleUpload() {
      if (this.uploadFileList.length === 0) {
        this.$message.warning('请先选择要上传的文件');
        return;
      }

      // 如果正在上传，则不允许重复启动
      if (this.batchUploading) {
        return;
      }

      this.batchUploading = true;
      this.uploadProgress = []; // 清空进度显示
      this.uploadedCount = 0; // 已上传完成的文件数量
      this.totalCount = 1; // 单文件模式，总数量为1
      this.uploadingFiles.clear(); // 清空正在上传的文件集合

      try {
        // 初始化进度显示
        const file = this.uploadFileList[0];
        this.uploadProgress[0] = {
          filename: file.name,
          status: 'uploading',
          percentage: 0
        };

        // 上传单个文件
        const fileKey = `${file.name}-${file.size}-${file.lastModified}`;
        if (!this.uploadingFiles.has(fileKey)) {
          this.uploadingFiles.add(fileKey);
          this.uploadSingleFile(file, 0, fileKey);
        }

      } catch (error) {
        console.error('单文件上传失败:', error);
        this.$message.error('单文件上传失败: ' + (error.message || '未知错误'));
        this.batchUploading = false;
      }
    },

    // 开始批量上传
    async startBatchUpload() {
      if (this.uploadFileList.length === 0) {
        this.$message.warning('请先选择要上传的文件');
        return;
      }

      // 如果正在上传，则不允许重复启动
      if (this.batchUploading) {
        return;
      }

      this.batchUploading = true;
      this.uploadProgress = []; // 清空进度显示
      this.uploadedCount = 0; // 已上传完成的文件数量
      this.totalCount = this.uploadFileList.length; // 总文件数量
      this.uploadingFiles.clear(); // 清空正在上传的文件集合

      try {
        // 初始化进度显示
        this.uploadFileList.forEach((file, index) => {
          this.uploadProgress[index] = {
            filename: file.name,
            status: 'uploading',
            percentage: 0
          };
        });

        // 异步同时调用上传接口
        this.uploadFileList.forEach((file, index) => {
          // 检查文件是否已经在上传
          const fileKey = `${file.name}-${file.size}-${file.lastModified}`;
          if (!this.uploadingFiles.has(fileKey)) {
            this.uploadingFiles.add(fileKey);
            this.uploadSingleFile(file, index, fileKey);
          }
        });

      } catch (error) {
        console.error('批量上传失败:', error);
        this.$message.error('批量上传失败: ' + (error.message || '未知错误'));
        this.batchUploading = false;
      }
    },

    // 上传单个文件
    async uploadSingleFile(file, index, fileKey) {
      try {
        // 模拟上传进度
        const progressInterval = setInterval(() => {
          if (this.uploadProgress[index].percentage < 90) {
            this.uploadProgress[index].percentage += 10;
          }
        }, 200);

        const response = await uploadFile(file.raw);
        
        clearInterval(progressInterval);
        
        if (response && response.data) {
          this.uploadProgress[index] = {
            filename: file.name,
            status: 'success',
            percentage: 100
          };
          
          // 更新文件列表
          const fileUrl = response.data.file_url || response.data.url;
          if (fileUrl) {
            if (this.multiple) {
              // 多文件模式：添加到现有列表
              this.fileList = [...this.fileList, fileUrl];
            } else {
              // 单文件模式：替换现有列表
              this.fileList = [fileUrl];
            }
            
            // 触发 change 事件
            this.$emit('change', this.fileList.join(','));
          }
          
          this.uploadedCount++;
          this.checkUploadComplete();
          
        } else {
          this.uploadProgress[index] = {
            filename: file.name,
            status: 'error',
            percentage: 0
          };
          
          this.uploadedCount++;
          this.checkUploadComplete();
        }
      } catch (error) {
        this.uploadProgress[index] = {
          filename: file.name,
          status: 'error',
          percentage: 0
        };
        
        console.error(`文件 ${file.name} 上传失败:`, error);
        
        this.uploadedCount++;
        this.checkUploadComplete();
      } finally {
        // 从正在上传的文件集合中移除
        if (fileKey) {
          this.uploadingFiles.delete(fileKey);
        }
      }
    },

    // 检查是否全部上传完成
    checkUploadComplete() {
      if (this.uploadedCount >= this.totalCount) {
        // 统计成功和失败的文件
        const successFiles = this.uploadProgress.filter(progress => progress.status === 'success');
        const failedFiles = this.uploadProgress.filter(progress => progress.status === 'error');
        
        if (successFiles.length > 0) {
          this.$message.success(`成功上传 ${successFiles.length} 个文件${failedFiles.length > 0 ? `，${failedFiles.length} 个文件上传失败` : ''}`);
        } else {
          this.$message.error('所有文件上传失败');
        }
        
        this.dialogVisible = false;
        this.uploadFileList = []; // 清空上传列表
        this.uploadProgress = []; // 清空进度显示
        this.uploadingFiles.clear(); // 清空正在上传的文件集合
        this.batchUploading = false;
      }
    }
  }
}
</script>

<style lang="scss">

.upload-container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 100%;
  }
.file-upload-wrapper {
  display: flex;
  flex-wrap: wrap;

}
.img-upload-box {
  display: flex;
  flex-wrap: wrap;
  .el-upload-list {
    display: none;
  }
  .avatar-uploader {
    width: 240px;
    height: 120px;
    margin-right: 8px;
    margin-bottom: 8px;
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;

    // 视频预览容器样式
    &.video-container {
      width: 240px;
      height: 120px;
    }
    &.multiple {
      width: 120px;
      height: 120px;
      .avatar-uploader-icon {
        font-size: 24px;
        width: 120px;
        height: 120px;
        line-height: 120px !important;
      }
      .avatar {
        width: 120px;
        height: 120px;
      }
    }
    .close-icon {
      position: absolute;
      right: -8px;
      top: -8px;
      font-size: 24px;
      color: #0bc162;
      cursor: pointer;
    }
    &.active {
      cursor: pointer;
      .close-icon {
        display: none;
      }
    }
  }

  .avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 240px;
    height: 120px;
    line-height: 120px !important;
    text-align: center;
  }
  .avatar {
    width: 240px;
    height: 120px;
    display: block;
  }
}

.upload-progress {
  margin-top: 20px;
  max-height: 200px;
  overflow-y: auto;
  
  .progress-item {
    margin-bottom: 15px;
    padding: 10px;
    border: 1px solid #e4e7ed;
    border-radius: 4px;
    background-color: #fafafa;
    
    .progress-info {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 8px;
      
      .filename {
        font-weight: 500;
        color: #303133;
        flex: 1;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        margin-right: 10px;
      }
      
      .status {
        font-size: 12px;
        padding: 2px 6px;
        border-radius: 3px;
        
        &.uploading {
          color: #409eff;
          background-color: #ecf5ff;
        }
        
        &.success {
          color: #67c23a;
          background-color: #f0f9ff;
        }
        
        &.error {
          color: #f56c6c;
          background-color: #fef0f0;
        }
      }
    }
  }
}
</style>


